use core::slice;
use std::slice::from_raw_parts;
use std::str::from_utf8_unchecked;

use crate::gen_title;

pub fn ch4_19_1() {
    gen_title("ch4_19_1", 18);

    let mut num = 5;
    let r1 = &num as *const i32;

    unsafe {
        println!("r1: {}", *r1);
    }
}

pub fn ch4_19_2() {
    gen_title("ch4_19_2", 18);

    let mut num = 5;

    let r1 = &num as *const i32;
    let r2 = &mut num as *mut i32;

    unsafe {
        println!("r1: {}, r2: {}", *r1, *r2);
    }
}

pub fn ch4_19_3() {
    gen_title("ch4_19_3", 18);

    fn get_memory_location() -> (usize, usize) {
        let string = "Hello World!";
        let pointer = string.as_ptr() as usize;
        let length = string.len();
        (pointer, length)
    }

    fn get_str_at_location(pointer: usize, length: usize) -> &'static str {
        unsafe { from_utf8_unchecked(from_raw_parts(pointer as *const u8, length)) }
    }

    let (pointer, length) = get_memory_location();
    let message = get_str_at_location(pointer, length);
    println!(
        "The {} bytes as 0x{:X} stored: {}",
        length, pointer, message
    );
}

pub fn ch4_19_4() {
    gen_title("ch4_19_4", 18);

    let a = 1;
    let b: *const i32 = &a as *const i32;
    let c: *const i32 = &a;

    unsafe {
        println!("{}", *c);
    }
}

pub fn ch4_19_5() {
    gen_title("ch4_19_5", 18);

    let a: Box<i32> = Box::new(11);
    let b: *const Box<i32> = &a;
    let c: *const i32 = Box::into_raw(a);

    unsafe {
        println!("{}", *c);
        println!("{:p}", c);
        println!("{}", *b);
        println!("{:p}", b);
    }
}

pub fn ch4_19_6() {
    gen_title("ch4_19_6", 18);

    fn split_at_mut(slice: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
        let len = slice.len();
        let ptr = slice.as_mut_ptr();

        assert!(mid <= len);

        unsafe {
            (
                slice::from_raw_parts_mut(ptr, mid),
                slice::from_raw_parts_mut(ptr.add(mid), len - mid),
            )
        }
    }

    let mut v = vec![1, 2, 3, 4, 5, 6];
    let r = &mut v[..];
    let (a, b) = split_at_mut(r, 3);

    assert_eq!(a, &mut [1, 2, 3]);
    assert_eq!(b, &mut [4, 5, 6]);

    println!("a: {:?}, b: {:?}", a, b);
}

pub fn ch4_19_7() {
    gen_title("ch4_19_7", 18);

    extern "C" {
        fn abs(input: i32) -> i32;
    }

    unsafe { println!("Absolute value of -3 according to C: {}", abs(-3)) }
}

// pub fn ch4_19_8() {
//     gen_title("ch4_19_8", 18);
//
//     unsafe {
//         asm!("nop");
//     }
// }
//
// pub fn ch4_19_9() {
//     gen_title("ch4_19_9", 18);
//
//     let x: u64;
//     unsafe {
//         asm!("mov {}, 5", out(reg) x);
//     }
//
//     assert_eq!(x, 5);
//     println!("x: {}", x);
// }
//
// pub fn ch4_19_10() {
//     gen_title("ch4_19_10", 18);
//
//     let i: u64 = 3;
//     let o: u64;
//     unsafe {
//         asm!(
//         "mov {0}, {1}",
//         "add {0}, 5",
//         out(reg) o,
//         in(reg) i,
//         )
//     }
//
//     assert_eq!(o, 8);
//     println!("o: {}", o);
// }
//
// pub fn ch4_19_11() {
//     gen_title("ch4_19_11", 18);
//
//     let mut x: u64 = 3;
//     unsafe {
//         asm!("add {0}, 5", inout(reg) x);
//     }
//     assert_eq!(x, 8);
//     println!("x: {}", x);
// }
//
// pub fn ch4_19_12() {
//     gen_title("ch4_19_12", 18);
//
//     let x: u64 = 3;
//     let y: u64;
//     unsafe {
//         asm!("add {0}, 5", inout(reg) x => y);
//     }
//     assert_eq!(y, 8);
//     println!("y: {}", y);
// }
//
// pub fn ch4_19_13() {
//     gen_title("ch4_19_13", 18);
//
//     let mut a: u64 = 4;
//     let b: u64 = 4;
//     unsafe {
//         asm!("add {0}, {1}", inlateout(reg) a, in(reg) b);
//     }
//     assert_eq!(a, 8);
//     println!("a: {}", a);
// }
//
// pub fn ch4_19_14() {
//     gen_title("ch4_19_14", 18);
//
//     let lo: u64;
//     let hi: u64;
//
//     let a: u64 = 4;
//     let b: u64 = 2;
//
//     unsafe {
//         asm!(
//         "mul {}",
//         in(reg) a,
//         inlateout("rax") b => lo,
//         lateout("rdx") hi
//         )
//     }
//
//     println!("lo: {}, hi: {}", lo, hi);
//     println!("{}", ((hi as u128) << 64) + lo as u128);
// }
//
// pub fn ch4_19_15() {
//     gen_title("ch4_19_15", 18);
//
//     let mut name_buf = [0_u8; 12];
//
//     unsafe {
//         asm! {
//         "push rbx",
//         "cpuid",
//         "mov [rdi], ebx",
//         "mov [rdi + 4], edx",
//         "mov [rdi + 8], ecx",
//         "pop rbx",
//         in("rdi") name_buf.as_mut_ptr(),
//         inout("eax") 0 => _,
//         out("ecx") _,
//         out("edx") _,
//         }
//     };
//
//     let name = core::str::from_utf8(&name_buf).unwrap();
//     println!("CPU Manufacturer ID: {}", name);
// }
